//////////////////////////////////////////////////////////////////////
//
// NO_Library.cpp: Implementierung der Klasse NO_Library.
//
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
#define NO_TAL_EXPORT

//////////////////////////////////////////////////////////////////////////
#include "NO_Externs.h"
#include "NO_Library.h"

//////////////////////////////////////////////////////////////////////////
typedef void *PluginLoad(void);
typedef void *PluginUnload(void);
typedef NO_Boolean *PluginTest(void);

//////////////////////////////////////////////////////////////////////////
NO_Library::RefCounter NO_Library::refCounter;

//////////////////////////////////////////////////////////////////////////
// con/destruction
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
NO_Library::NO_Library(const NO_Int8* libname)
{
	name = libname;
	id = noGetHash(libname);
	lib = LoadLibrary(libname);
	if(!lib){throw std::exception("Module loading error");}
	
	RefCounter::iterator iter = refCounter.find(id);
	if(iter == refCounter.end())
	{
		refCounter[id] = 1;
		PluginLoad* f = (PluginLoad*)GetProcAddress(lib,"loadPlugin");
		if(!f){throw std::exception("Module load function not found.");}
		(*f)();
	}
	else{(++(iter->second));}
	
	std::cout<<"Module: "<<libname<<" loaded."<<std::endl;
}

//////////////////////////////////////////////////////////////////////
NO_Library::~NO_Library()
{
	if(!lib){return;}

	RefCounter::iterator iter = refCounter.find(id);
	if(iter == refCounter.end()){throw std::exception("Module reference table corruption.");}

	(--(iter->second));
	if(iter->second==0)
	{
		refCounter.erase(iter);
		PluginUnload* f = (PluginUnload*)GetProcAddress(lib,"unloadPlugin");
		if(!f){throw std::exception("Module unload function not found.");}
		(*f)();
	}
	
	NO_Boolean done = FreeLibrary(lib)!=0;
	if(!done){throw std::exception("Module unloading error.");}
	
	std::cout<<"Module: "<<name<<" unloaded."<<std::endl;
}

//////////////////////////////////////////////////////////////////////////
// use
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
void NO_Library::test(void)
{
	if(!lib){return;}
	PluginTest* f = (PluginTest*)GetProcAddress(lib,"testPlugin");
	if(!f){throw std::exception("Module test function not found.");}
	NO_Boolean good = (*f)();
	
	std::cout<<"Module: "<<name<<" test "<<(good?"passed.":"failed.")<<std::endl;
}

//////////////////////////////////////////////////////////////////////////
// retrieve
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
const std::string&	NO_Library::getName			(void) const{return name;}
	  NO_UInt32		NO_Library::getID			(void) const{return id;}

//////////////////////////////////////////////////////////////////////////
NO_UInt32 NO_Library::getReferences	(void) const
{
	RefCounter::const_iterator iter = refCounter.find(id);
	NO_Boolean found = iter != refCounter.end();
	if (!found){return 0;}	
	return iter->second;
}

